package com.guozcc.bootweb.platform.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.guozcc.bootweb.platform.annotation.Lock;;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@Aspect//定义通知、切点关系
//@Order(value = 1)//多个切面的执行顺序  执行顺序从小到大
public class LockAspect {
    @Autowired
    private RedissonClient redissonClient;

    final private String lockNamePre = "lock";

    @Pointcut("@annotation(com.guozcc.bootweb.platform.annotation.Lock)")
    public void lockAspectPointcut(){

    }

    @Around("lockAspectPointcut()")
    public Object lock(ProceedingJoinPoint joinPoint) throws Throwable {
        /**
         * 获取类、方法以及注解相关信息
         */
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = method.getName();

        Lock lockAnnotation = method.getAnnotation(Lock.class);
        String lockName = lockAnnotation.lockName();
        if(StringUtils.isEmpty(lockName)){
            throw new Exception("未指定锁");
        }
        long lockTime = lockAnnotation.lockTime();
        TimeUnit timeUnit = lockAnnotation.timeUnit();

        /**
         * 获取锁名称
         */
        Object[] args = joinPoint.getArgs();
        JSONObject requestJson = JSONObject.parseObject(JSON.toJSONString(args[0]));
        String lockValue = lockNamePre+":"
                +className+"."+methodName+":"
                +lockName+":"+requestJson.get(lockName);

        /**
         * 执行目标方法
         */
        Object result = null;
        RLock redissonLock = redissonClient.getLock(lockValue);
        try{
            redissonLock.lock(lockTime,timeUnit);
            log.info("分布式锁开启："+lockValue);

            result = joinPoint.proceed(args);
        }catch (Exception e){
            log.error("",e);
            result =new JSONObject(){{
                put("ec","99999");
                put("em","执行异常");
            }};
        }finally {
            redissonLock.unlock();
            log.info("分布式锁解除："+lockValue);
        }
        return result;
    }
}
